#include <algorithm>
#include <cmath>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <tuple>
#include <vector>

#include "BarkerPair.h"

#define INITIAL_POPULATION 1024

std::vector<int> generateRandomBinarySequence(int length) {
    std::random_device rd;                          
    std::default_random_engine rng(rd());           
    std::uniform_int_distribution<int> dist(0, 1);  

    std::vector<int> sequence;
    sequence.reserve(length);

    for (int i = 0; i < length; ++i) {
        int num = dist(rng);                    
        sequence.push_back(num == 0 ? -1 : 1);  
    }

    return sequence;
}

int getRandomNumber(int min, int max) {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(min, max);
    return dis(gen);
}

float getRandomFloat() {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(0.0, 1.0);
    return dis(gen);
}

std::tuple<int, int, double> init(int argc, char* argv[]) {
    int iterationCount = 100;
    int maximumPopulationSize = 1e4;
    double mutationRate = 0.8;

    if (argc > 1) {
        iterationCount = std::stoi(argv[1]);
    }
    if (argc > 2) {
        maximumPopulationSize = std::stoi(argv[2]);
    }
    if (argc > 3) {
        mutationRate = std::stod(argv[3]);
    }
    return std::make_tuple(iterationCount, maximumPopulationSize, mutationRate);
}

std::vector<BarkerPair> generate(int length) {
    std::vector<BarkerPair> generations;
    for (int i = 0; i < INITIAL_POPULATION; ++i) {
        generations.push_back(BarkerPair{generateRandomBinarySequence(length),
                                         generateRandomBinarySequence(length)});
    }
    return generations;
}

int main(int argc, char* argv[]) {
    std::cout << "=============================" << std::endl;

    auto [iterationCount, maximumPopulationSize, mutationRate] =
        init(argc, argv);

    int length = 0;
    std::cout << "please input length:" << std::endl;
    std::cin >> length;

    std::vector<BarkerPair> generations = generate(length);

    int currentGeneration = 1;
    do {
        std::sort(generations.begin(), generations.end());
        std::cout << generations[0] << std::endl;
        if (currentGeneration % iterationCount == 0) {
            std::ofstream outputFile("bcp-" + std::to_string(length) + "-" +
                                     std::to_string(currentGeneration) +
                                     ".txt");
            if (!outputFile.is_open()) {
                std::cerr << "Error opening the file." << std::endl;
                return -1;
            }

            for (int i = 0; i < generations.size(); ++i) {
                outputFile << generations[i] << "\n";
            }
            outputFile.close();
            std::cout << "saved generation: " << currentGeneration << std::endl;
        }

        std::vector<BarkerPair> nextGenerations;
        nextGenerations.reserve(maximumPopulationSize);

        // 添加更多精英个体
        for (int i = 0; i < 4; ++i) {
            nextGenerations.push_back(generations[i]);
        }

        while (nextGenerations.size() < maximumPopulationSize) {
            // 锦标赛选择两个父代
            int idx1 = getRandomNumber(0, generations.size() / 2);
            int idx2 = getRandomNumber(0, generations.size() / 2);

            std::vector<int> x1 = generations[idx1].x;
            std::vector<int> y1 = generations[idx1].y;
            std::vector<int> x2 = generations[idx2].x;
            std::vector<int> y2 = generations[idx2].y;

            std::vector<int> x{x1};
            std::vector<int> y{y1};
            for (int i = 0; i < length; ++i) {
                if (getRandomNumber(0, 1)) {
                    x[i] = x1[i];
                    y[i] = y1[i];
                } else {
                    x[i] = x2[i];
                    y[i] = y2[i];
                }

                // 增加变异率
                if (getRandomFloat() < mutationRate) {
                    x[i] = -x[i];
                }
                if (getRandomFloat() < mutationRate) {
                    y[i] = -y[i];
                }
            }
            BarkerPair child{x, y};
            nextGenerations.push_back(child);
        }

        generations = std::move(nextGenerations); // 使用移动语义提高效率
        currentGeneration++;
    } while (true);

    std::cout << std::endl << "=============================" << std::endl;
}
